package com.violet.gateway.auth;

import com.violet.auth.client.service.impl.DefaultPermissionServiceImpl;
import com.violet.common.entity.Permission;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @Author: wqf
 * @Date: 2024/09/10
 * @Description: 经过认证管理器JwtAuthenticationManager认证成功后，就需要对令牌进行鉴权，如果该令牌无访问资源的权限，则不允通过
 * 权限校验
 */
@Slf4j
@Component
public class PermissionAuthManager extends DefaultPermissionServiceImpl implements ReactiveAuthorizationManager<AuthorizationContext> {

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
        //认证通过且角色匹配的用户可访问当前路径
        return mono.map(auth -> {
            ServerWebExchange exchange = authorizationContext.getExchange();
            ServerHttpRequest request = exchange.getRequest();
            boolean isPermission = super.hasPermission(auth, request.getMethodValue(), request.getURI().getPath());
            return new AuthorizationDecision(isPermission);
        }).defaultIfEmpty(new AuthorizationDecision(false));
    }

    @Override
    public List<Permission> findMenuByRoleCodes(String roleCodes) {
//        Future<List<Menu>> futureResult = asynMenuService.findByRoleCodes(roleCodes);
        Future<List<Permission>> futureResult = new Future<List<Permission>>() {
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                return false;
            }

            @Override
            public boolean isCancelled() {
                return false;
            }

            @Override
            public boolean isDone() {
                return false;
            }

            @Override
            public List<Permission> get() throws InterruptedException, ExecutionException {
                return List.of();
            }

            @Override
            public List<Permission> get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
                return List.of();
            }
        };
        try {
            return futureResult.get();
        } catch (Exception e) {
            log.error("asynMenuService.findMenuByRoleCodes-error", e);
        }
        return Collections.emptyList();
    }
}
